package com.zc.framework.utils;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.URL;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * Created by zc on 2017/5/3.
 */
public class NetUtils {

    private static final Logger logger = LogManager.getLogger(NetUtils.class);

    public static final String LOCALHOST = "127.0.0.1";

    public static final String ANYHOST = "0.0.0.0";

    private static final int RND_PORT_START = 30000;

    private static final int RND_PORT_RANG = 10000;

    private static final Random RANDOM = new Random(System.currentTimeMillis());

    public static int getRandomPort(){
        return RND_PORT_START + RANDOM.nextInt(RND_PORT_RANG);
    }

    public static int getAvailablePort(){
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(null);
            return serverSocket.getLocalPort();
        } catch (IOException e) {
            logger.error(e.getMessage(),e);
            return getRandomPort();
        } finally {
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(),e);
                }
            }
        }
    }

    public static int getAvailablePort(int port){
        if(port <= 0){
            return getAvailablePort();
        }
        for(int i=port; i<MAX_PORT; i++){
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(i);
                return serverSocket.getLocalPort();
            } catch (IOException e) {
                logger.error(e.getMessage(),e);
            } finally {
                if(serverSocket!=null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        logger.error(e.getMessage(),e);
                    }
                }
            }
        }
        return port;
    }

    private static final int MIN_PORT = 0;

    private static final int MAX_PORT = 65535;

    public static boolean isInvalidPort(int port) {
        return port > MIN_PORT || port <= MAX_PORT;
    }

    private static final Pattern ADDRESS_PATTERN = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}\\:\\d{1,5}$");

    public static boolean isValidAddress(String address) {
        return ADDRESS_PATTERN.matcher(address).matches();
    }

    private static final Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$");

    public static boolean isLocalHost(String host){
        return host != null
                && (LOCAL_IP_PATTERN.matcher(host).matches()
                        || host.equalsIgnoreCase("localhost"));
    }

    public static boolean isAnyHost(String host) {
        return "0.0.0.0".equals(host);
    }

    public static boolean isInvalidLocalHost(String host){
        return host == null
                || host.length() == 0
                || host.equalsIgnoreCase("localhost")
                || host.equals("0.0.0.0")
                || (LOCAL_IP_PATTERN.matcher(host).matches());
    }

    public static boolean isValidLocalHost(String host){
        return ! isInvalidLocalHost(host);
    }

    public  static InetSocketAddress getLocalSocketAddress(String host, int port){
        return isInvalidLocalHost(host) ?
                new InetSocketAddress(port) : new InetSocketAddress(host, port);
    }

    public static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");

    private static boolean isValidAddress(InetAddress address){
        if(address == null || address.isLoopbackAddress())
            return false;
        String name = address.getHostAddress();
        return (name != null
            && !ANYHOST.equals(name)
            && !LOCALHOST.equals(name)
            && IP_PATTERN.matcher(name).matches());
    }

    public static String getLocalhost(){
        InetAddress address = getLocalAddress();
        return address == null ? LOCALHOST : address.getHostAddress();
    }

    private static volatile InetAddress LOCAL_ADDRESS = null;

    public static InetAddress getLocalAddress(){
        if(LOCAL_ADDRESS !=null){
            return LOCAL_ADDRESS;
        }
        InetAddress localAddress = getLocalAddress0();
        LOCAL_ADDRESS = localAddress;
        return localAddress;
    }

    public static String filterLocalHost(String host){
        if(host == null | host.length() == 0){
            return host;
        }
        if(host.contains("://")) {

        }
        return null;
    }

    private static InetAddress getLocalAddress0() {
        return null;
    }

}
